/******************************************************************************
 *  A Teaching GA					  Developed by Hal Stringer & Annie Wu, UCF
 *  Version 2, January 18, 2004
 *******************************************************************************/

import java.io.*;
import java.util.*;
import java.text.*;

public class Search {

	/*******************************************************************************
	 * INSTANCE VARIABLES *
	 *******************************************************************************/

	/*******************************************************************************
	 * STATIC VARIABLES *
	 *******************************************************************************/

	public static FitnessFunction problem;

	public static Chromo[] member;
	public static Chromo[] child;

	public static Chromo bestOfGenChromo;
	public static int bestOfGenR;
	public static int bestOfGenG;
	public static Chromo bestOfRunChromo;
	public static int bestOfRunR;
	public static int bestOfRunG;
	public static Chromo bestOverAllChromo;
	public static Chromo minBestOverAllChromo;
	public static Chromo firstGenBestOverAllChromo;
	public static Chromo lastGenBestOverAllChromo;
	public static int bestOverAllR;
	public static int bestOverAllG;

	public static double sumRawFitness;
	public static double sumRawFitness2; // sum of squares of fitness
	public static double sumSclFitness;
	public static double sumProFitness;
	public static double defaultBest;
	public static double defaultWorst;

	public static double averageRawFitness;
	public static double stdevRawFitness;

	public static int G;
	public static int R;
	public static Random r = new Random();
	private static double randnum;

	private static int memberIndex[];
	private static double memberFitness[];
	private static int TmemberIndex;
	private static double TmemberFitness;

	private static double fitnessStats[][]; // 0=Avg, 1=Best

	private static int optIndiGen[];
	private static int optValue = 200;
	private static double fitnessStatsAvg[][];
	private static double fitnessStatsBest[][];

	private static double fitnessBestOfRuns[];
	
	private static double runBestFitness[];  // best fitness of each run
	private static int runBestGenNum[];  // best fitness generation number
	private static double allRunBestFit[][];  // all runs best fitness
	private static double allRunAvgFit[][];  // all runs average fitness
	private static double allRunStdFit[][];  // all runs average fitness
	private static double allRunFit[][][]; // fitness of all indvs in all runs and all gens
	

	/*******************************************************************************
	 * CONSTRUCTORS *
	 *******************************************************************************/

	/*******************************************************************************
	 * MEMBER METHODS *
	 *******************************************************************************/

	/*******************************************************************************
	 * STATIC METHODS *
	 *******************************************************************************/

	public static void main(String[] args) throws java.io.IOException {

		Calendar dateAndTime = Calendar.getInstance();
		Date startTime = dateAndTime.getTime();

		SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss");
		Date date = new Date();
		String sDate = sdf.format(date);

		// Read Parameter File
		System.out.println("\nParameter File Name is: " + args[0] + "\n");
		Parameters parmValues = new Parameters(args[0]);

		// Write Parameters To Summary Output File
		String summaryFileName = Parameters.expID + "_" + sDate+".txt";
		FileWriter summaryOutput = new FileWriter(summaryFileName);
		parmValues.outputParameters(summaryOutput);

		//  matlab output file format
		String summaryFileNameMatlab = Parameters.expID + "_pop_" + Parameters.popSize
														+ "_mut_" + Parameters.mutationRate
														+ "_xover_" + Parameters.xoverRate
														+ "_sclt_" + Parameters.selectType
														+ "_st_" + Parameters.stratType
														+ "_output.m";
		FileWriter summaryOutputMatlab = new FileWriter(summaryFileNameMatlab);

		// Set up Fitness Statistics matrix
		fitnessStats = new double[2][Parameters.generations];
		for (int i = 0; i < Parameters.generations; i++) {
			fitnessStats[0][i] = 0;
			fitnessStats[1][i] = 0;
		}
		
		//	initialize all run best and average fitness matrix
		allRunAvgFit = new double[Parameters.numRuns][Parameters.generations];
		allRunStdFit = new double[Parameters.numRuns][Parameters.generations];
		allRunBestFit = new double[Parameters.numRuns][Parameters.generations];
		allRunFit = new double[Parameters.numRuns][Parameters.generations][Parameters.popSize];
		for (int i=0; i<Parameters.numRuns; i++){
			for (int j=0; j<Parameters.generations; j++){
				allRunAvgFit [i][j] = 0;
				allRunStdFit [i][j] = 0;
				allRunBestFit [i][j] = 0;
				for (int k=0; k < Parameters.popSize; k++)
					allRunFit [i][j][k] = 0;
			}
		}
		
		//	Set up Fitness Statistics matrix for best fitness of each run
		runBestFitness = new double[Parameters.numRuns];
		runBestGenNum = new int[Parameters.numRuns];
		for (int i=0; i<Parameters.numRuns; i++){
			runBestFitness[i] = 0;
			runBestGenNum[i] = 0;
		}

		// Setup Fitness data collection
		fitnessStatsAvg = new double[Parameters.numRuns][Parameters.generations];
		fitnessStatsBest = new double[Parameters.numRuns][Parameters.generations];
		fitnessBestOfRuns = new double[Parameters.numRuns];

		for (int i = 0; i < Parameters.numRuns; i++) {
			for (int j = 0; j < Parameters.generations; j++) {
				fitnessStatsAvg[i][j] = 0;
				fitnessStatsBest[i][j] = 0;
			}
			fitnessBestOfRuns[i] = 0;
		}
		// Problem Specific Setup - For new new fitness function problems,
		// create
		// the appropriate class file (extending FitnessFunction.java) and add
		// an else_if block below to instantiate the problem.

		if (Parameters.problemType.equals("NM")) {
			problem = new NumberMatch();
		} else if (Parameters.problemType.equals("OM")) {
			problem = new OneMax();
		} else if (Parameters.problemType.equals("PD")) {
			problem = new PrisonersDilemmaProblem();
		} else
			System.out.println("Invalid Problem Type");

		System.out.println(problem.name);

		// Initialize RNG, array sizes and other objects
		r.setSeed(Parameters.seed);
		memberIndex = new int[Parameters.popSize];
		memberFitness = new double[Parameters.popSize];
		member = new Chromo[Parameters.popSize];
		child = new Chromo[Parameters.popSize];
		bestOfGenChromo = new Chromo();
		bestOfRunChromo = new Chromo();
		bestOverAllChromo = new Chromo();
		minBestOverAllChromo = new Chromo();
		firstGenBestOverAllChromo = new Chromo();
		lastGenBestOverAllChromo = new Chromo();

		if (Parameters.minORmax.equals("max")) {
			defaultBest = 0;
			defaultWorst = 999999999999999999999.0;
		} else {
			defaultBest = 999999999999999999999.0;
			defaultWorst = 0;
		}

		bestOverAllChromo.rawFitness = defaultBest;
		minBestOverAllChromo.rawFitness = defaultBest;
		firstGenBestOverAllChromo.rawFitness = defaultBest;
		lastGenBestOverAllChromo.rawFitness = defaultBest;

		optIndiGen = new int[Parameters.numRuns];

		// Start program for multiple runs
		for (R = 0; R < Parameters.numRuns; R++) {

			optIndiGen[R] = 0;
			bestOfRunChromo.rawFitness = defaultBest;
			// System.out.println();

			// Initialize First Generation
			for (int i = 0; i < Parameters.popSize; i++) {
				member[i] = new Chromo();
				child[i] = new Chromo();
			}

			// Begin Each Run
			/*
			 * summaryOutput.write("R   "); summaryOutput.write("G   ");
			 * summaryOutput.write("bstChmFit   ");
			 * summaryOutput.write("avgFit   ");
			 * summaryOutput.write("stdDiv   "); summaryOutput.write("\n");
			 */
			for (G = 0; G < Parameters.generations; G++) {

				sumProFitness = 0;
				sumSclFitness = 0;
				sumRawFitness = 0;
				sumRawFitness2 = 0;
				bestOfGenChromo.rawFitness = defaultBest;

				// Test Fitness of Each Member
				problem.doFitnessForPopulation(member);
				
				for (int i = 0; i < Parameters.popSize; i++) {

					//member[i].rawFitness = 0;
					member[i].sclFitness = 0;
					member[i].proFitness = 0;

					//problem.doFitnessAgainstPopulation(member);

					sumRawFitness = sumRawFitness + member[i].rawFitness;
					sumRawFitness2 = sumRawFitness2 + member[i].rawFitness
							* member[i].rawFitness;

					if (Parameters.minORmax.equals("max")) {
						if (member[i].rawFitness > bestOfGenChromo.rawFitness) {
							Chromo.copyB2A(bestOfGenChromo, member[i]);
							bestOfGenR = R;
							bestOfGenG = G;
						}
						if (member[i].rawFitness > bestOfRunChromo.rawFitness) {
							Chromo.copyB2A(bestOfRunChromo, member[i]);
							fitnessBestOfRuns[R] = member[i].rawFitness;
							bestOfRunR = R;
							bestOfRunG = G;
						}
						if (member[i].rawFitness > bestOverAllChromo.rawFitness) {
							Chromo.copyB2A(bestOverAllChromo, member[i]);
							bestOverAllR = R;
							bestOverAllG = G;
						}
						if (member[i].rawFitness == optValue) {
							if (optIndiGen[R] == 0) {
								optIndiGen[R] = G;
							}
						}
						if (0 == G) {
							if (member[i].rawFitness > firstGenBestOverAllChromo.rawFitness) {
								Chromo.copyB2A(firstGenBestOverAllChromo, member[i]);
							}
						}
						if (G == (Parameters.generations-1)) {
							if (member[i].rawFitness > lastGenBestOverAllChromo.rawFitness) {
								Chromo.copyB2A(lastGenBestOverAllChromo, member[i]);
							}
						}
					} else {
						if (member[i].rawFitness < bestOfGenChromo.rawFitness) {
							Chromo.copyB2A(bestOfGenChromo, member[i]);
							bestOfGenR = R;
							bestOfGenG = G;
						}
						if (member[i].rawFitness < bestOfRunChromo.rawFitness) {
							Chromo.copyB2A(bestOfRunChromo, member[i]);
							bestOfRunR = R;
							bestOfRunG = G;
						}
						if (member[i].rawFitness < bestOverAllChromo.rawFitness) {
							Chromo.copyB2A(bestOverAllChromo, member[i]);
							bestOverAllR = R;
							bestOverAllG = G;
						}
						if ((member[i].rawFitness == optValue)
								&& (optIndiGen[R] == 0)) {
							optIndiGen[R] = G;
						}
					}
				}
				
				if (bestOfGenChromo.rawFitness < minBestOverAllChromo.rawFitness) {
					Chromo.copyB2A(minBestOverAllChromo, bestOfGenChromo);
				}
				if (minBestOverAllChromo.rawFitness == 0) {
					Chromo.copyB2A(minBestOverAllChromo, bestOfGenChromo);
				}

				// Accumulate fitness statistics
				fitnessStats[0][G] += sumRawFitness / Parameters.popSize;
				fitnessStats[1][G] += bestOfGenChromo.rawFitness;

				fitnessStatsAvg[R][G] = sumRawFitness / Parameters.popSize;
				fitnessStatsBest[R][G] = bestOfGenChromo.rawFitness;
				
				allRunAvgFit[R][G] = sumRawFitness / Parameters.popSize;
				allRunBestFit[R][G] = bestOfGenChromo.rawFitness;

				averageRawFitness = sumRawFitness / Parameters.popSize;
				stdevRawFitness = Math.sqrt(Math.abs(sumRawFitness2
						- sumRawFitness * sumRawFitness / Parameters.popSize)
						/ (Parameters.popSize - 1));

				// Output generation statistics to screen
				System.out.println(R + "\t" + G + "\t"+ (int)
				 bestOfGenChromo.rawFitness + "\t" + averageRawFitness + "\t"
				 + stdevRawFitness);
				/*
				 * // Output generation statistics to summary file //
				 * summaryOutput.write(" R "); Hwrite.right(R, 3,
				 * summaryOutput); // summaryOutput.write(" G ");
				 * Hwrite.right(G, 3, summaryOutput); Hwrite.right((int)
				 * bestOfGenChromo.rawFitness, 7, summaryOutput);
				 * Hwrite.right(averageRawFitness, 11, 3, summaryOutput);
				 * Hwrite.right(stdevRawFitness, 11, 3, summaryOutput);
				 * summaryOutput.write("\n");
				 */
				// *********************************************************************
				// **************** SCALE FITNESS OF EACH MEMBER AND SUM
				// ***************
				// *********************************************************************

				switch (Parameters.scaleType) {

				case 0: // No change to raw fitness
					for (int i = 0; i < Parameters.popSize; i++) {
						member[i].sclFitness = member[i].rawFitness + .000001;
						sumSclFitness += member[i].sclFitness;
					}
					break;

				case 1: // Fitness not scaled. Only inverted.
					for (int i = 0; i < Parameters.popSize; i++) {
						member[i].sclFitness = 1 / (member[i].rawFitness + .000001);
						sumSclFitness += member[i].sclFitness;
					}
					break;

				case 2: // Fitness scaled by Rank (Maximizing fitness)

					// Copy genetic data to temp array
					for (int i = 0; i < Parameters.popSize; i++) {
						memberIndex[i] = i;
						memberFitness[i] = member[i].rawFitness;
					}
					// Bubble Sort the array by floating point number
					for (int i = Parameters.popSize - 1; i > 0; i--) {
						for (int j = 0; j < i; j++) {
							if (memberFitness[j] > memberFitness[j + 1]) {
								TmemberIndex = memberIndex[j];
								TmemberFitness = memberFitness[j];
								memberIndex[j] = memberIndex[j + 1];
								memberFitness[j] = memberFitness[j + 1];
								memberIndex[j + 1] = TmemberIndex;
								memberFitness[j + 1] = TmemberFitness;
							}
						}
					}
					// Copy ordered array to scale fitness fields
					for (int i = 0; i < Parameters.popSize; i++) {
						member[memberIndex[i]].sclFitness = i;
						sumSclFitness += member[memberIndex[i]].sclFitness;
					}

					break;

				case 3: // Fitness scaled by Rank (minimizing fitness)

					// Copy genetic data to temp array
					for (int i = 0; i < Parameters.popSize; i++) {
						memberIndex[i] = i;
						memberFitness[i] = member[i].rawFitness;
					}
					// Bubble Sort the array by floating point number
					for (int i = 1; i < Parameters.popSize; i++) {
						for (int j = (Parameters.popSize - 1); j >= i; j--) {
							if (memberFitness[j - i] < memberFitness[j]) {
								TmemberIndex = memberIndex[j - 1];
								TmemberFitness = memberFitness[j - 1];
								memberIndex[j - 1] = memberIndex[j];
								memberFitness[j - 1] = memberFitness[j];
								memberIndex[j] = TmemberIndex;
								memberFitness[j] = TmemberFitness;
							}
						}
					}
					// Copy array order to scale fitness fields
					for (int i = 0; i < Parameters.popSize; i++) {
						member[memberIndex[i]].sclFitness = i;
						sumSclFitness += member[memberIndex[i]].sclFitness;
					}

					break;

				default:
					System.out.println("ERROR - No scaling method selected");
				}

				// *********************************************************************
				// ****** PROPORTIONALIZE SCALED FITNESS FOR EACH MEMBER AND SUM
				// *******
				// *********************************************************************

				for (int i = 0; i < Parameters.popSize; i++) {
					member[i].proFitness = member[i].sclFitness / sumSclFitness;
					sumProFitness = sumProFitness + member[i].proFitness;
				}

				// *********************************************************************
				// ************ CROSSOVER AND CREATE NEXT GENERATION
				// *******************
				// *********************************************************************

				int parent1 = -1;
				int parent2 = -1;

				// Assumes always two offspring per mating
				for (int i = 0; i < Parameters.popSize; i = i + 2) {
 
					// Select Two Parents
					parent1 = Chromo.selectParent();
					parent2 = parent1;
					while (parent2 == parent1) {
						parent2 = Chromo.selectParent();
					}

					// Crossover Two Parents to Create Two Children
					randnum = r.nextDouble();
					if (randnum < Parameters.xoverRate) {
						Chromo.mateParents(parent1, parent2, member[parent1],
								member[parent2], child[i], child[i + 1]);
					} else {
						Chromo.mateParents(parent1, member[parent1], child[i]);
						Chromo.mateParents(parent2, member[parent2],
								child[i + 1]);
					}
				} // End Crossover

				// Mutate Children
				for (int i = 0; i < Parameters.popSize; i++) {
					child[i].doMutation();
				}

				// Swap Children with Last Generation
				for (int i = 0; i < Parameters.popSize; i++) {
					Chromo.copyB2A(member[i], child[i]);
				}

				double c_std = 0;
				for (int i_s=0; i_s < Parameters.popSize; i_s++){
					double subt = allRunAvgFit[R][G]-allRunFit[R][G][i_s];
					c_std += java.lang.Math.pow(subt, 2);
				}
				c_std = c_std/Parameters.popSize;
				allRunStdFit[R][G] = java.lang.Math.sqrt(c_std);

			} // Repeat the above loop for each generation

			summaryOutput.write("#Run  ");
			Hwrite.left(bestOfRunR, 4, summaryOutput);
			summaryOutput.write("bstGen  ");
			Hwrite.right(bestOfRunG, 4, summaryOutput);
			summaryOutput.write("\r\n");
			summaryOutput.write("Best of Run");
			summaryOutput.write("\r\n");

			problem.doPrintGenes(bestOfRunChromo, summaryOutput);

			// System.out.println(R + "\t" + "B" + "\t" + (int)
			// bestOfRunChromo.rawFitness);

			System.out.println(R + "\t" + "B" + "\t"+ bestOfRunChromo.rawFitness);
			runBestFitness[R] = bestOfRunChromo.rawFitness;
			runBestGenNum[R] = bestOfRunG;

		} // End of a Run

		Hwrite.left("#B", 8, summaryOutput);
		summaryOutput.write("best Over All chromo \n");
		summaryOutput.write("#R: " + bestOverAllR + "  G: " + bestOverAllG
				+ "  Fitness: " + bestOverAllChromo.rawFitness + "\n");

		problem.doPrintGenes(bestOverAllChromo, summaryOutput);

		//RCM
		summaryOutput.write("\r\n Minimum best Over All chromo \r\n");
		summaryOutput.write("Fitness: " + minBestOverAllChromo.rawFitness + "\r\n");
		problem.doPrintGenes(minBestOverAllChromo, summaryOutput);

		summaryOutput.write("\r\n First Generation best Over All chromo \r\n");
		summaryOutput.write("Fitness: " + firstGenBestOverAllChromo.rawFitness + "\r\n");
		problem.doPrintGenes(firstGenBestOverAllChromo, summaryOutput);
		
		summaryOutput.write("\r\n Last Generation best Over All chromo \r\n");
		summaryOutput.write("Fitness: " + lastGenBestOverAllChromo.rawFitness + "\r\n");
		problem.doPrintGenes(lastGenBestOverAllChromo, summaryOutput);
		//RCM
		
		double[] tempAvg = new double[Parameters.numRuns];
		double[] tempBest = new double[Parameters.numRuns];
		// Output Fitness Statistics matrix
		summaryOutput.write("#Gen      AvgFit    stdDev    BestFit   stdDev\n");
		for (int i = 0; i < Parameters.generations; i++) {
			Hwrite.left(i, 10, summaryOutput);
			// Average average fitness and standard deviation, averaged over 50
			// run
			Hwrite.left(fitnessStats[0][i] / Parameters.numRuns, 10, 2,
					summaryOutput);
			for (int j = 0; j < Parameters.numRuns; j++) {
				tempAvg[j] = fitnessStatsAvg[j][i];
				tempBest[j] = fitnessStatsBest[j][i];
			}
			Hwrite.left(stdDeviationDouble(tempAvg), 10, 2, summaryOutput);

			// Average best fitness and standard deviation over 50 run
			Hwrite.left(fitnessStats[1][i] / Parameters.numRuns, 10, 2,
					summaryOutput);
			Hwrite.left(stdDeviationDouble(tempBest), 10, 2, summaryOutput);

			summaryOutput.write("\n");
		}

		System.out.println("#Overall Best Individual Fitness: "
				+ bestOverAllChromo.rawFitness);
		summaryOutput.write("#Overall Best Individual Fitness: "
				+ bestOverAllChromo.rawFitness + "\n");
		System.out.println("-----------------------------");
		System.out
				.println("#Average best fitness over 50 run, standard deviation, and 95% confidence interval");
		confidenceIntervalDouble(fitnessBestOfRuns, summaryOutput);
		System.out.println("-----------------------------");
		System.out
				.println("#Average generation that an optimal individual is found over 50 run"
						+ "\n"
						+ "the standard deviation and 95% confidence interval");
		confidenceIntervalInt(optIndiGen, summaryOutput);
		System.out.println("-----------------------------");

		System.out.println("Data plot file: "+ summaryFileName + " created in same directory");
		System.out.println("Start:  " + startTime);
		summaryOutput.write(" \n #Start:  " + startTime);

		dateAndTime = Calendar.getInstance();
		Date endTime = dateAndTime.getTime();
		System.out.println("End  :  " + endTime);
		summaryOutput.write("\n #End  :  " + endTime);

		summaryOutput.write("\n");
		summaryOutput.close();

		// write average fitness in matlab file
		summaryOutputMatlab.write("clear all; clc; close all;\n");
		summaryOutputMatlab.write("avgFit=[");
		for (int i=0; i<Parameters.generations; i++){
			Hwrite.left(fitnessStats[0][i]/Parameters.numRuns, 20, 2, summaryOutputMatlab);
			summaryOutputMatlab.write("\n");
		}
		summaryOutputMatlab.write("];\n");
		
		summaryOutputMatlab.write("bestFit=[");
		for (int i=0; i<Parameters.generations; i++){
			Hwrite.left(fitnessStats[1][i]/Parameters.numRuns, 20, 2, summaryOutputMatlab);
			summaryOutputMatlab.write("\n");
		}
		summaryOutputMatlab.write("];\n");

		summaryOutputMatlab.write("bestEachRunFit=[");
		for (int i=0; i<Parameters.numRuns; i++){
			Hwrite.left(runBestFitness[i], 20, 2, summaryOutputMatlab);
			summaryOutputMatlab.write("\n");
		}
		summaryOutputMatlab.write("];\n");

		summaryOutputMatlab.write("bestEachRunGen=[");
		for (int i=0; i<Parameters.numRuns; i++){
			Hwrite.left(runBestGenNum[i], 20, 2, summaryOutputMatlab);
			summaryOutputMatlab.write("\n");
		}
		summaryOutputMatlab.write("];\n");

		summaryOutputMatlab.write("allRunBestFit=[");
		for (int i=0; i<Parameters.numRuns; i++){
			for (int j=0; j<Parameters.generations; j++){
				Hwrite.left(allRunBestFit[i][j], 20, 2, summaryOutputMatlab);
				summaryOutputMatlab.write(",");
			}
			summaryOutputMatlab.write("\n");
		}
		summaryOutputMatlab.write("];\n");

		summaryOutputMatlab.write("allRunAvgFit=[");
		for (int i=0; i<Parameters.numRuns; i++){
			for (int j=0; j<Parameters.generations; j++){
				Hwrite.left(allRunAvgFit[i][j], 20, 2, summaryOutputMatlab);
				summaryOutputMatlab.write(",");
			}
			summaryOutputMatlab.write("\n");
		}
		summaryOutputMatlab.write("];\n");
		summaryOutputMatlab.write("\n");

		summaryOutputMatlab.write("allRunStdFit=[");
		for (int i=0; i<Parameters.numRuns; i++){
			for (int j=0; j<Parameters.generations; j++){
				Hwrite.left(allRunStdFit[i][j], 20, 2, summaryOutputMatlab);
				summaryOutputMatlab.write(",");
			}
			summaryOutputMatlab.write("\n");
		}
		summaryOutputMatlab.write("];\n");
		summaryOutputMatlab.write("\n");

		summaryOutputMatlab.write("figure(1);\n");
		summaryOutputMatlab.write("plot(mean(allRunAvgFit), 'color', 'r', 'linewidth', 2);\n");
		summaryOutputMatlab.write("hold on;\n");
		summaryOutputMatlab.write("plot(mean(allRunBestFit), 'color', 'b', 'linewidth', 2);\n");
		summaryOutputMatlab.write("legend('avg avg fit','avg best fit', 'Location', 'NorthEast');\n");
		summaryOutputMatlab.write("hold off;\n");
		summaryOutputMatlab.write("set(gcf, 'color', [1 1 1]);\n");
		summaryOutputMatlab.write("xlabel('Generations');\n");
		summaryOutputMatlab.write("ylabel('Fitness');\n");
		summaryOutputMatlab.write("plotf = getframe(gcf);\n");
		summaryOutputMatlab.write("imwrite(plotf.cdata,'1.tif', 'tiff');\n");
		summaryOutputMatlab.write("\n");

		summaryOutputMatlab.write("figure(2);\n");
		summaryOutputMatlab.write("plot(std(allRunAvgFit), 'color', 'r', 'linewidth', 2);\n");
		summaryOutputMatlab.write("hold on;\n");
		summaryOutputMatlab.write("plot(std(allRunBestFit), 'color', 'b', 'linewidth', 2);\n");
		summaryOutputMatlab.write("legend('std avg fit','std best fit', 'Location', 'NorthEast');\n");
		summaryOutputMatlab.write("hold off;\n");
		summaryOutputMatlab.write("set(gcf, 'color', [1 1 1]);\n");
		summaryOutputMatlab.write("xlabel('Generations');\n");
		summaryOutputMatlab.write("ylabel('Fitness');\n");
		summaryOutputMatlab.write("plotf = getframe(gcf);\n");
		summaryOutputMatlab.write("imwrite(plotf.cdata,'2.tif', 'tiff');\n");
		summaryOutputMatlab.write("\n");
		
		
		summaryOutputMatlab.write("[muhat,sigmahat,muci,sigmaci] = normfit(bestEachRunFit);\n");
		summaryOutputMatlab.write("display(['mean best fit: ' num2str(muhat)]);\n");
		summaryOutputMatlab.write("display(['std best fit: ' num2str(sigmahat)]);\n");
		summaryOutputMatlab.write("display(['95% CI mean best fit: (' num2str(muci(1)) ',' num2str(muci(2)) ')']);\n");
		summaryOutputMatlab.write("display(['95% CI std best fit: (' num2str(sigmaci(1)) ',' num2str(sigmaci(2)) ')']);\n");
		summaryOutputMatlab.write("clear muhat sigmahat muci sigmaci;\n");

		summaryOutputMatlab.write("[muhat,sigmahat,muci,sigmaci] = normfit(bestEachRunGen);\n");
		summaryOutputMatlab.write("display(['mean best fit gen: ' num2str(muhat)]);\n");
		summaryOutputMatlab.write("display(['std best fit gen: ' num2str(sigmahat)]);\n");
		summaryOutputMatlab.write("display(['95% CI mean best fit gen: (' num2str(muci(1)) ',' num2str(muci(2)) ')']);\n");
		summaryOutputMatlab.write("display(['95% CI std best fit gen: (' num2str(sigmaci(1)) ',' num2str(sigmaci(2)) ')']);\n");
		summaryOutputMatlab.write("clear muhat sigmahat muci sigmaci;\n");

		summaryOutputMatlab.write("[muhat,sigmahat,muci,sigmaci] = normfit(bestEachRunGen(bestEachRunFit>.9999999));\n");
		summaryOutputMatlab.write("display(['mean optimum gen: ' num2str(muhat)]);\n");
		summaryOutputMatlab.write("display(['std optimum gen: ' num2str(sigmahat)]);\n");
		summaryOutputMatlab.write("display(['95% CI mean optimum gen: (' num2str(muci(1)) ',' num2str(muci(2)) ')']);\n");
		summaryOutputMatlab.write("display(['95% CI std optimum gen: (' num2str(sigmaci(1)) ',' num2str(sigmaci(2)) ')']);\n");
		summaryOutputMatlab.write("clear muhat sigmahat muci sigmaci;\n");
		
		summaryOutputMatlab.close();
		

	} // End of Main Class

	public static double stdDeviationDouble(double[] a) {
		int n = a.length;
		// System.out.println("count: "+ n);
		double sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + a[i];
		}
		double mean = sum / n;
		// System.out.println("mean: "+ mean);
		sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + Math.pow((a[i] - mean), 2);
		}
		return Math.sqrt(sum / (n - 1));
	}

	public static double stdDeviationInt(int[] a) {
		int n = a.length;
		// System.out.println("count: "+ n);
		double sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + a[i];
		}
		double mean = sum / n;
		// System.out.println("mean: "+ mean);
		sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + Math.pow((a[i] - mean), 2);
		}
		return Math.sqrt(sum / (n - 1));
	}

	public static void confidenceIntervalInt(int[] a, FileWriter writer) {
		int n = a.length;
		// System.out.println("count: "+ n);
		double sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + a[i];
		}
		double mean = sum / n;
		// System.out.println("mean: "+ mean);
		sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + Math.pow((a[i] - mean), 2);
		}
		double stddev = Math.sqrt(sum / (n - 1));

		double lo = mean - 1.96 * stddev;
		double hi = mean + 1.96 * stddev;
		System.out.println("average          = " + mean);
		System.out.println("sample stddev    = " + stddev);
		System.out.println("95% approximate confidence interval");
		System.out.println("[ " + lo + ", " + hi + " ]");

		try {
			writer.write("#-----------------------------" + "\n");
			writer.write("#Average generation that an optimal individual is found over 50 run"
					+ ", the standard deviation and 95% confidence interval"
					+ "\n");
			writer.write("#average          = " + mean + "\n");
			writer.write("#sample stddev    = " + stddev + "\n");
			writer.write("#95% approximate confidence interval" + "\n");
			writer.write("#[ " + lo + ", " + hi + " ]" + "\n");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public static double average(int[] a) {
		int n = a.length;
		// System.out.println("count: "+ n);
		double sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + a[i];
		}
		double mean = sum / n;
		return mean;
	}

	public static void confidenceIntervalDouble(double[] a, FileWriter writer) {
		int n = a.length;
		// System.out.println("count: "+ n);
		double sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + a[i];
		}
		double mean = sum / n;
		// System.out.println("mean: "+ mean);
		sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum = sum + Math.pow((a[i] - mean), 2);
		}
		double stddev = Math.sqrt(sum / (n - 1));

		double lo = mean - 1.96 * stddev;
		double hi = mean + 1.96 * stddev;
		System.out.println("average          = " + mean);
		System.out.println("sample stddev    = " + stddev);
		System.out.println("95% approximate confidence interval");
		System.out.println("[ " + lo + ", " + hi + " ]");

		try {
			writer.write("#-----------------------------" + "\n");
			writer.write("#Average best fitness over 50 run, standard deviation, and 95% confidence interval \n");
			writer.write("#average          = " + mean + "\n");
			writer.write("#sample stddev    = " + stddev + "\n");
			writer.write("#95% approximate confidence interval" + "\n");
			writer.write("#[ " + lo + ", " + hi + " ]" + "\n");
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

} // End of Search.Java ******************************************************

